Skip to content

gh-145685: Improve scaling of type attribute lookups#145774

Merged
colesbury merged 2 commits intopython:mainfrom
colesbury:gh-145685-lock-free-type-lookup
Mar 12, 2026
Merged

gh-145685: Improve scaling of type attribute lookups#145774
colesbury merged 2 commits intopython:mainfrom
colesbury:gh-145685-lock-free-type-lookup

Conversation

@colesbury
Copy link
Contributor

@colesbury colesbury commented Mar 10, 2026

Avoid locking in the PyType_Lookup cache-miss path if the type's tp_version_tag is already valid.

Avoid locking in the PyType_Lookup cache-miss path if the type's
tp_version_tag is already valid.
@colesbury colesbury added the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Mar 10, 2026
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @colesbury for commit 68c122c 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F145774%2Fmerge

If you want to schedule another build, you need to add the 🔨 test-with-refleak-buildbots label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Mar 10, 2026
@colesbury colesbury marked this pull request as ready for review March 10, 2026 19:25
@colesbury colesbury requested a review from markshannon as a code owner March 10, 2026 19:25
@colesbury colesbury requested a review from mpage March 10, 2026 19:25
Copy link
Contributor

@mpage mpage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth adding a test case to the scaling benchmark?

END_TYPE_LOCK();
}
else {
res = find_name_in_mro(type, name, out);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to hold the type lock around this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The operations in find_name_in_mro are individually thread-safe, although this allows for mutations to types to be interleaved with the MRO traversal. I think that's acceptable. There were already edge cases where that could happen due to ensure_shared_on_read() calls suspending the critical section during dictionary lookups in find_name_in_mro.

Importantly, if any type in the MRO chain is modified during lookup, the assigned version tag will be stale so any future cache lookups won't use it.

@colesbury
Copy link
Contributor Author

Would it be worth adding a test case to the scaling benchmark?

This improves the scaling behavior, but it's not enough to scale linearly so I don't want to add a benchmark to ftscalingbench.py yet.

Here's the benchmark I've occasionally used locally: https://gist.github.com/colesbury/7d43e7dde89c1cb5574b5a2c73cc52b1

Some of the remaining issues:

  1. The code keeps getting re-specialized and the specialization code itself causes reference count contention. This seems fixable in follow up PRs

  2. Seq-lock contention in the MRO cache. This is trickier.

@colesbury colesbury merged commit cd52172 into python:main Mar 12, 2026
71 checks passed
@miss-islington-app
Copy link

Thanks @colesbury for the PR 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖 I'm not a witch! I'm not a witch!

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Mar 12, 2026
…145774)

Avoid locking in the PyType_Lookup cache-miss path if the type's
tp_version_tag is already valid.
(cherry picked from commit cd52172)

Co-authored-by: Sam Gross <colesbury@gmail.com>
@bedevere-app
Copy link

bedevere-app bot commented Mar 12, 2026

GH-145874 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.14 bugs and security fixes label Mar 12, 2026
colesbury added a commit that referenced this pull request Mar 12, 2026
… (#145874)

Avoid locking in the PyType_Lookup cache-miss path if the type's
tp_version_tag is already valid.

(cherry picked from commit cd52172)

Co-authored-by: Sam Gross <colesbury@gmail.com>
@bedevere-bot
Copy link

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 Ubuntu Shared 3.14 (tier-1) has failed when building commit cedff2d.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/1802/builds/838) and take a look at the build logs.
  4. Check if the failure is related to this commit (cedff2d) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/1802/builds/838

Failed tests:

  • test_pyrepl

Failed subtests:

  • test_repl_eio - test.test_pyrepl.test_unix_console.TestUnixConsoleEIOHandling.test_repl_eio

Summary of the results of the build (if available):

==

Click to see traceback logs
Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/subprocess.py", line 1138, in __del__
    _warn("subprocess %s is still running" % self.pid,
ResourceWarning: subprocess 3913832 is still running
Warning -- Unraisable exception
Exception ignored while finalizing file <_io.FileIO name=10 mode='rb' closefd=True>:
Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/unittest/case.py", line 668, in run
    with outcome.testPartExecutor(self):
ResourceWarning: unclosed file <_io.TextIOWrapper name=10 encoding='UTF-8'>
Warning -- Unraisable exception
Exception ignored while finalizing file <_io.FileIO name=8 mode='rb' closefd=True>:
Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/unittest/case.py", line 668, in run
    with outcome.testPartExecutor(self):
ResourceWarning: unclosed file <_io.TextIOWrapper name=8 encoding='UTF-8'>


Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/test/test_pyrepl/test_unix_console.py", line 390, in test_repl_eio
    _, err = proc.communicate(timeout=support.LONG_TIMEOUT)
             ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/subprocess.py", line 1220, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
                     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/subprocess.py", line 2153, in _communicate
    self._check_timeout(endtime, orig_timeout, stdout, stderr)
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/subprocess.py", line 1267, in _check_timeout
    raise TimeoutExpired(
    ...<2 lines>...
            stderr=b''.join(stderr_seq) if stderr_seq else None)
subprocess.TimeoutExpired: Command '['/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/python', '-E', '-S', '/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/test/test_pyrepl/eio_test_script.py']' timed out after 300.0 seconds


Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/subprocess.py", line 1138, in __del__
    _warn("subprocess %s is still running" % self.pid,
ResourceWarning: subprocess 3900353 is still running
Warning -- Unraisable exception
Exception ignored while finalizing file <_io.FileIO name=10 mode='rb' closefd=True>:
Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/unittest/case.py", line 668, in run
    with outcome.testPartExecutor(self):
ResourceWarning: unclosed file <_io.TextIOWrapper name=10 encoding='UTF-8'>
Warning -- Unraisable exception
Exception ignored while finalizing file <_io.FileIO name=8 mode='rb' closefd=True>:
Traceback (most recent call last):
  File "/srv/buildbot/buildarea/3.14.bolen-ubuntu/build/Lib/unittest/case.py", line 668, in run
    with outcome.testPartExecutor(self):
ResourceWarning: unclosed file <_io.TextIOWrapper name=8 encoding='UTF-8'>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants